package com.beiding.dao;


import org.bson.Document;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.*;

public interface ResourceOperations<T> extends CommonOperations<T> {


    //holderId字段集合
    static Map<String, Field> holderIdFields = new HashMap<>();

    /**
     * 检查资源持有者
     *
     * @param id       被检查的资源ID
     * @param holderId 持有者ID
     * @return true if id对应的实体属于holderId
     */
    default boolean checkHolder(String id, String holderId) {
        Assert.notNull(holderId, holderIdFieldName() + " can't be null");

        Optional<T> optional = findByIdLimitFields(id, holderIdFieldName());

        if (optional.isPresent()) {
            T t = optional.get();

            Class<?> type = type();

            Field field = holderIdFields.get(type.getName());

            if (field == null) {

                //如果在当前类中没有holderId字段就查看其父类是否具有
                while (type != Object.class) {
                    try {
                        field = type.getDeclaredField(holderIdFieldName());
                        break;
                    } catch (NoSuchFieldException e) {
                    }
                    type = type.getSuperclass();
                }

                if (field != null) {
                    field.setAccessible(true);
                    holderIdFields.put(type.getName(), field);
                }
            }


            if (field == null)
                return false;

            Object o = null;
            try {
                o = field.get(t);
            } catch (IllegalAccessException e) {
                return false;
            }
            return holderId.equals(o);
        }
        return false;
    }


    default List<T> findByHolderInPage(String holderId, Pageable pageable, List<String> limitFields) {
        Assert.notNull(holderId, holderIdFieldName() + " can't be null");
        List<T> r = null;
        Document q = new Document();
        q.put(holderIdFieldName(), holderId);
        Document f = new Document();
        limitFields.forEach(
                it -> f.put(it, true)
        );
        return mongoOperations().find(new BasicQuery(q, f).with(pageable), type());
    }

    /**
     * 以持有者分页获取资源
     *
     * @param holderId    持有者ID
     * @param page        页数
     * @param pageSize    每页条目
     * @param limitFields 限制的字段
     * @return
     */
    default List<T> findByHolderInPage(String holderId, int page, int pageSize, List<String> limitFields) {
        return findByHolderInPage(holderId, PageRequest.of(page, pageSize), limitFields);
    }

    /**
     * 以持有者分页获取资源
     *
     * @param holderId    持有者ID
     * @param page        页数
     * @param pageSize    每页条目
     * @param limitFields 限制的字段.如果限定字段长度为0,则显示全部字段
     * @return
     */
    default List<T> findByHolderInPage(String holderId, int page, int pageSize, String... limitField) {
        Assert.notNull(holderId, holderIdFieldName() + " can't be null");

        List<T> r = null;
        PageRequest p = PageRequest.of(page, pageSize);
        if (limitField.length == 0) {
            return mongoOperations().find(Query.query(Criteria.where(holderIdFieldName()).is(holderId)).with(p), type());
        } else {
            return findByHolderInPage(holderId, page, pageSize, Arrays.asList(limitField));
        }
    }

    default List<T> findByHolderInPage(String holderId, Pageable pageable, String... limitField) {
        Assert.notNull(holderId, holderIdFieldName() + " can't be null");

        List<T> r = null;
        if (limitField.length == 0) {
            return mongoOperations().find(Query.query(Criteria.where(holderIdFieldName()).is(holderId)).with(pageable), type());
        } else {
            return findByHolderInPage(holderId, pageable, Arrays.asList(limitField));
        }
    }


    /**
     * 根据持有者来计数
     *
     * @param holderId 持有者Id
     * @return
     */
    default long countResources(String holderId) {
        Assert.notNull(holderId, holderIdFieldName() + " can't be null");
        return mongoOperations().count(Query.query(Criteria.where(holderIdFieldName()).is(holderId)), type());
    }

    /**
     * 清空持有者所持有的所有资源
     *
     * @param holderId 持有者Id
     */
    default void deleteByHolder(String holderId) {
        mongoOperations().findAllAndRemove(Query.query(Criteria.where(holderIdFieldName()).is(holderId)), type());
    }

    /**
     * @return holderId字段的实际名称
     */
    default String holderIdFieldName() {
        return "holderId";
    }

}
